home *** CD-ROM | disk | FTP | other *** search
- ;--------------------------------------------------------------------------
- ;------------------------------- 26TIME v1.0 ----------------------------
- ;--------------------------------------------------------------------------
- ;
- ; PROGRAM 26TIME
- ; VERSION 2.0
- ; AUTHOR PETER NELSON
- ;
- ; DESCRIPTION:
- ;
- ; This program works with the IBM CGA cards, IBM MONO cards, Hercules
- ; cards, and Compaqs. It resets the graphics chip to display 26 instead of
- ; the normal 25 rows of text on the screen. On the 26th line is
- ; displayed the time, updated Once per minute. It is theoretically
- ; possible to use this program with a normal graphics card. You would
- ; have to put the time in the upper right corner, and check 18
- ; times/second to see if it had scrolled off the screen yet. If it
- ; had, you would have to redisplay it. This program checks
- ; twice/second the the color of the lower-right character of the
- ; screen. It then prints the 26th row that color, and displays the
- ; time using that color too. This makes it look good no matter what
- ; program you are running. If the color of the lower-right character
- ; changes, it redraws the entire bottom line, including the time. Every
- ; time the time is displayed, there is a quiet "tick" sound made. It
- ; is possible to have the seconds being displayed as they change, or
- ; have the colon flash once/second, but I decided this would eat up too
- ; much processor power.
- ;
- ; REVISIONS:
- ;
- ; VERSION # AUTHOR DESCRIPTION
- ;
- ; 1.1 Peter Nelson Some programs would blank the screen by
- ; a hardware method that also ended up blanking
- ; my time display. Added a check to see if
- ; the last position on the 26th line had an
- ; 'm'. If not, I redisplayed. This makes it
- ; compatible with Lotus-123.
- ; 1.2 Peter Nelson Fixed bug. If it was 12:00 (noon or
- ; midnight), the am/pm indicator would be
- ; wrong. Now is correct.
- ; 1.3 Peter Nelson Prints time one space to the left of the
- ; right edge of the lowest line now.
- ; 2.0 Peter Nelson Now works with IBM Mono cards, Compaqs, and
- ; Hercules cards.
- ;
- ;
- ;------------------------------ INCLUDES --------------------------------
-
- include \asm\macros.asm ; defines the IFR macro
- include \asm\equates.asm ; has many generally used values equated
-
- ;------------------------------ EQUATES ---------------------------------
- ;
- ; These are equates I would probably NEVER use in any other program.
-
- COMPAQ_CO EQU 'OC' ; Value of 'CO'(ompaq) stored in mem
- COMPAQ_SEG EQU 0F000h ; Location of 'COMPAQ' if a compaq
- COMPAQ_OFF EQU 0FFEAh ; computer is being used.
-
-
- ;------------------------------ PUBLICS ---------------------------------
- ;
- ; The public directive allows the use of these labels by the symbolic
- ; debugger (SYMDEB).
-
-
- public start, begin, setvectors, int18_routine, int18_cont1, exit
- public checkrow, check_cont0, check_cont1, checkrow_exit
- public checkrow_exit_fine, checkrow_exit, showtime, show_cont1, show_cont2
- public show_cont3, showtime_exit, conv, convloop, conv_cont1, conv_exit
- public showword, showbyte, shownib, show_c1, display_al, click, veryend
- public checkrow_ret, checkrow_exit_reshow
-
- public intvector, counter1, convtable, hours, mins, secs, count, message
- public counter1, counter2, screen_page, attribute, flag
-
-
- ;------------------------------ SEGMENT ---------------------------------
-
- code segment ; It must orginate at 0100h
- assume ds:code, cs:code, es:code ; or else it can't be a .COM
- org 0100h ; file and mem-resident.
-
- ;------------------------------- START ----------------------------------
-
- start: ; make sure DS=CS and jump around data
- push cs
- pop ds
- jmp begin
-
- ;------------------------------- DATA -----------------------------------
- ;
- ; Be sure to use the CS: override for all the data in this program
- ; since this is a memory resident routine, and we can't be sure of the
- ; state of the [ds] register.
-
-
- intvector dw 0 ; This defines two words (a doubleword) to hold
- dw 0 ; the address of the old timer routine.
- counter1 dw 0 ; A counter for determining when check bottom line
- counter2 dw 0 ; Another counter for determining when to display
- attribute db 0 ; Stores the screen attribute of the lower line
- screen_page db 0 ; stores the screen page being viewed
- mode db 0 ; stores the screen mode we are in
- flag db 0 ; indicates a redisplay is neccessary
- card db 0 ; =0 if CGA, =1 if Mono, =2 if Compaq graphics card
- hours db 00 ; stores the hours
- mins db 00 ; stores the minutes
- secs db 00 ; stores the seconds
- count dw 0000 ; stores the count of seconds since midnight
- dw 0000
-
- message db cr,lf,cr,lf,cr,lf
- db ' 26TIME Version 2.0 3-DEC-86',cr,lf,cr,lf
- db ' This program was written in MASM 4.0 by Peter Nelson. It is a memory',cr,lf
- db ' resident program that occupies 1.8 k-bytes (1856) of ram. The current time',cr,lf
- db ' will be displayed on the 26th line of the screen at all times. It will not',cr,lf
- db ' interfere with graphing. It will work with the IBM-CGA, the IBM Mono card',cr,lf
- db ' the Hercules graphics card, and Compaqs. Mono & Herc cards will display',cr,lf
- db ' garbage on the right half of the lower line. ENJOY!',cr,lf,cr,lf,'$'
-
- convtable db 01h,02h,04h,08h,016h,032h,064h ; used for bin-dec convert
-
-
-
- ;------------------------------ PROGRAM ---------------------------------
-
- begin:
- mov ah, 9 ; display logo
- mov dx, offset message
- int msdos
-
- whatcard: ; figure out what graphics card used
- mov cs:card, 0 ; the default adapter is the CGA
-
- mov cx, bios_data_seg ; segment of bios data bytes
- mov es, cx
- mov al, byte ptr es:equip_flag ; get the first byte of the
- and al, 00110000b ; equip list, and isolate the crt
- cmp al, 00110000b ; switches. If they are set so, then
- ifr e <mov cs:card, 1> ; we are using a monographics card.
-
- mov cx, compaq_seg ; if this memory location holds
- mov es, cx ; 'CO' then this is a compaq
- cmp word ptr es:compaq_off, compaq_co ; computer
- ifr e <mov cs:card, 2>
-
- setvectors:
- mov ah, 035h ; use DOS interrupt function 35h to find the
- mov al, 01Ch ; current location of the timer interrupt
- int msdos ; routine. Save that location in
- mov intvector, bx ; [intvector].
- mov intvector+2, es
-
- push cs ; Point the timer interrupt
- pop ds ; to my program using DOS
- mov dx, offset int18_routine ; interrupt function 25h
- mov ah, 025h
- mov al, 01Ch
- int msdos
-
- mov dx, offset veryend ; terminate and stay in
- int terminate_stay_resident ; memory using DOS int. 27h
-
-
-
- ;------------------------------ ROUTINES --------------------------------
-
- int18_routine: ; this routine is called 18.2 times/second
- pushall ; Save all the registers and the flags.
-
- inc cs:counter2 ; this counter is used to
- cmp cs:counter2, 1092 ; display time once/minute
-
- ;** uncomment this and comment above line to display seconds
- ; cmp cs:counter2, 18 ; display time once/second
- ;**
- jb int18_cont1
- mov cs:counter2, 0
- call showtime
-
- int18_cont1:
- inc cs:counter1 ; this counter is used to check
- cmp cs:counter1, 9 ; the row color twice/second
- jb exit
- mov cs:counter1, 0
- call checkrow
- cmp cs:flag, 0
- je exit
- mov cs:counter2, 1091 ; make time display next timer tick
-
- exit:
- popall ; restore all the registers and flags
-
- jmp dword ptr cs:[intvector] ; branch to the original
- ; timer interrupt routine
-
- ;--------------------------------------------------------------------------
-
- checkrow: ; this routine is called twice/second
- mov ah, 0Fh ; see what video mode we are in
- int screen
- cmp al, 7
- je check_cont0a ; mode = 7 if hercules card
- cmp al, 3
- ifr a <jmp checkrow_ret> ; mode = 3-6 if in graphics mode
- check_cont0a:
- cmp cs:mode, al ; see if the mode changed
- je short check_cont0
- mov cs:attribute, 0 ; and make it redraw if changed
- mov cs:mode, al ; by making the color-check part fail
-
- check_cont0:
- mov ah, 0Fh ; save the cursor in the [si] reg
- int screen
- mov bl, al ; save the mode in [bl]
- mov ah, 3
- int screen
- mov si, dx
-
- cmp cs:screen_page, bh ; if the page being viewed changes,
- je check_cont1 ; be sure to keep up with it.
- mov cs:screen_page, bh ; change the attribute to 0
- mov cs:attribute, 0 ; so the time will be redrawn
-
- check_cont1:
- mov di, 0 ; to indicate 80 column mode, [di]=0
- cmp bl, 2
- ifr b <mov di, 1> ; to indicate 40 column mode, [di]=1
-
- mov ah, 2 ; put the cursor at the end of the 26th
- mov dh, 25 ; line and see if there is an 'm' there.
- mov dl, 78 ; if not, then something must have
- cmp di, 1 ; erased the screen. set cs:attribute
- ifr e <mov dl, 38> ; to 0 so the next little bit will catch it
- cmp cs:card, 1 ; and redraw the bottom line. Make sure if
- ifr e <mov dl, 7> ; we are using a herc card that we check
- int screen ; positions 6 and 7 too.
- mov ah, 8
- int screen
- cmp cs:card, 1 ; if not using a herc, check 'al' and see
- jne check_cont1a ; if it equals 'm'
- cmp al, 'm' ; if so, the check anyways and jump if it
- je check_cont1a ; is equal 'm'. If not, check position
- mov dl, 6 ; 6 on the screen.
- mov ah, 2
- mov dh, 25
- int screen
- mov ah, 8
- int screen
- check_cont1a:
- cmp al, 'm'
- ifr ne <mov cs:attribute, 0>
-
- mov ah, 2 ; set cursor to y=24, x=end-of-row
- mov dh, 24
- ; mov dl, 0 ; uncomment this and comment-out the next
- mov dl, 79 ; three lines if you want x=start-of-row
- cmp di, 1
- ifr e <mov dl, 39>
- int screen
- mov ah, 8 ; read the color there
- int screen
- cmp cs:attribute, ah ; leave now if its the same
- je checkrow_exit_fine
- mov cs:attribute, ah ; else save the new color and change screen
- mov bl, ah ; save the color in [bl]
- mov ah, 2 ; set the cursor to the 26th line, 1st pos.
- mov dh, 25
- mov dl, 0
- int screen
- mov al, ' ' ; and print spaces across the 26th row
- mov cx, 80
- cmp di, 1
- ifr e <mov cx, 40>
- mov ah, 9
- int screen
-
- checkrow_exit_reshow:
- mov cs:flag, 1
- jmp short checkrow_exit
-
- checkrow_exit_fine:
- mov cs:flag, 0
-
- checkrow_exit:
- mov ah, 0Fh ; restore the cursor position
- int screen
- mov ah, 02
- mov dx, si ; get position from [si]
- int screen
-
- checkrow_ret:
- ret
-
- ;--------------------------------------------------------------------------
-
- showtime: ; this is called once/minute, and when
- ; the screen color changes.
- mov ah, 0Fh ; see what video mode we are in
- int screen
- cmp al, 7 ; mode=7 if hercules card.
- je showtime_cont
- cmp al, 3
- ifr a <jmp showtime_exit> ; and don't print if in graphics mode
- showtime_cont:
- call click ; make a nice 'tick' sound
-
- mov ah, 0
- int time_of_day
-
- mov ax, dx ; divide ticks by 91
- mov dx, cx
- mov bx, 91
- div bx
-
- mov cx, dx ; and save the remainder in [cx]
-
- mov bx, 5 ; multiply result by 5
- mul bx
- mov cs:count, ax
- mov cs:count+2, dx ; save the result in [count]
-
- mov ax, cx ; divide the remainder (saved in [cx])
- mov dx, 0 ; by 18. This is the same as dividing by
- mov bx, 18 ; 18.2. I can't divide by 18 first because
- div bx ; at midnight this would give me a result
- ; greater than 0FFFFh. The margin of error
- ; is small. 32 seconds at midnight, less
- ; earlier in the day.
-
- add ax, cs:count ; add the result into [count] then save.
- mov cs:count, ax ; [count] now holds the total number of
- ; elapsed seconds since midnight (DOS).
-
- mov ax, cs:count ; divide the secs-since-midnight by 3600
- mov dx, cs:count+2 ; to get the hours since the start of the day
- mov bx, 3600
- div bx ; hours are now in [AL]. remainder
- mov cs:hours, al ; is in [DL]
-
- mov ax, dx ; divide the remainder by 60 to get the
- mov bl, 60 ; minutes since the start of the hour
- div bl
- mov cs:mins, al ; is in [AH]
-
- mov cs:secs, ah ; seconds are the remainder from above.
- ; [hours] now has the current hour in
- ; military format. [mins] has the current
- ; minutes. [secs] the current seconds.
-
-
-
- mov ah, 0Fh ; get current screen info
- int screen
- mov bl, al ; save the mode in [bl]
- mov ah, 3
- int screen
- mov si, dx ; save the cursor position in [si]
-
- mov dl, 71 ; set up x-pos to print time at. 40cols=32
- cmp bl, 2 ; 80cols=72.
- ifr b <mov dl, 31>
- ;** uncomment this and comment above 3 lines if you want to display seconds
- ; mov dl, 68 ; set up x-pos to print time at. 40cols=32
- ; cmp bl, 2 ; 80cols=72.
- ; ifr b <mov dl, 28>
- ;**
- cmp cs:card, 1 ; if this is a hercules card the print at
- ifr e <mov dl, 0> ; beginning of the line, instead of end
-
- mov bh, cs:screen_page ; set cursor position, y=26, x=[dl] reg.
- mov ah, 2
- mov dh, 25
- int screen
-
- cmp cs:card, 0 ; find out which graphics card is active,
- ifr e <call setcga> ; and call the appropriate routine to set
- cmp cs:card, 1 ; the card to 26 lines. I must do this
- ifr e <call setmono> ; each time I display the time cuz some
- cmp cs:card, 2 ; program (lotus) incessantly reset it.
- ifr e <call setcompaq>
-
- mov al, cs:hours ; show the time in standard format (AM/PM)
- mov di, 'a' ; set the [di] reg to 'a'
- cmp al, 24
- jne show_cont0a
- mov al, 0 ; take care of the 32 second error in my
- mov cs:secs, 0 ; so it is 12:00:00 midnight for 32 seconds
- show_cont0a:
- cmp al, 12
- ifr ae <mov di, 'p'> ; if hours >= 12 then it is 'pm', not 'am'.
- jbe show_cont1 ; here we convert from military to standard.
- sub al, 12 ; subtract 12 from hours.
- show_cont1:
- cmp al, 0 ; if hours=0 then it's midnight
- jne show_cont1a
- mov al, 12
- mov di, 'a' ; and it is 'am', at midnight
- show_cont1a:
- cmp al, 10 ; if there is only 1 digit in the hours
- jae show_cont2 ; (1:00-9:00) then don't print a leading
- mov ah, al ; zero, so we have to call shownib instead
- mov al, ' ' ; of show byte.
- cmp cs:card, 1 ; if this is a hercules card then we are
- ifr ne <call display_al> ; printing at start of line, so don't
- mov al, ah ; a leading space.
- call conv
- call shownib
- jmp short show_cont3
- show_cont2:
- call conv ; here the hours are between 10:00 and 12:00
- call showbyte ; so print the whole byte.
- show_cont3:
- mov al, ':' ; display a colon
- call display_al
- mov al, cs:mins ; display the minutes, leading zeros are
- call conv ; neccessary.
- call showbyte
-
- ;** uncomment this to display seconds
- ; mov al, ':' ; un-comment this to display the seconds.
- ; call display_al ; you must also then change the position
- ; mov al, cs:secs ; where the time is printed on the line, and
- ; call conv ; must change the cs:counter2 check so the
- ; call showbyte ; routine is called more frequently.
- ;**
- mov al, ' '
- call display_al ; here we display either ' am' or ' pm'
- mov ax, di
- call display_al
- mov al, 'm'
- call display_al
-
- mov ah, 0Fh ; restore the cursor position
- int screen
- mov ah, 02
- mov dx, si ; get position from [si]
- int screen
-
- showtime_exit:
- ret
-
- ;--------------------------------------------------------------------------
-
- setmono:
- mov dx, 03B4h ; I could make this a little table or
- mov al, 4 ; something, but it would take more
- out dx, al ; processing time, and I want this to run
- inc dx ; as fast as possible. Here I move the
- mov al, 26 ; value 26 into register 4 of the graphics
- out dx, al ; chip.
-
- dec dx ; register 5, value 3
- mov al, 5
- out dx, al
- inc dx
- mov al, 3
- out dx, al
-
- dec dx ; register 6, value 26
- mov al, 6
- out dx, al
- inc dx
- mov al, 26
- out dx, al
-
- dec dx ; register 7, value 26
- mov al, 7
- out dx, al
- inc dx
- mov al, 26
- out dx, al
-
- setmono_exit:
- ret
-
- ;--------------------------------------------------------------------------
-
- setcompaq: ; Note that the output port is different
- mov dx, 03D4h ; than the mono graphics adapter routine's,
- mov al, 4 ; but it is otherwise identical.
- out dx, al ; register 4, value 26
- inc dx
- mov al, 26
- out dx, al
-
- dec dx ; register 5, value 3
- mov al, 5
- out dx, al
- inc dx
- mov al, 3
- out dx, al
-
- dec dx ; register 6, value 26
- mov al, 6
- out dx, al
- inc dx
- mov al, 26
- out dx, al
-
- dec dx ; register 7, value 26
- mov al, 7
- out dx, al
- inc dx
- mov al, 26
- out dx, al
-
- setcompaq_exit:
- ret:
-
- ;--------------------------------------------------------------------------
-
- setcga:
- mov dx, 03d4h ; make the screen 26 lines long
- mov al, 6 ; this is done by setting register #6 of the
- out dx, al ; CGA card to 26. It is possible to get
- mov dx, 03d5h ; as many as 29 rows of text with a CGA.
- mov al, 26
- out dx, al
- setcga_exit:
- ret
-
- ;--------------------------------------------------------------------------
-
- conv: ; in: [al] contains the number to convert.
- push bp ; it must be less than 063h hex. out:
- push cx ; [al] is now converted. [ah] is destroyed
-
- mov bp, 0 ; use the DAA operand to add up the value of
- mov ah, al ; the lower 7 bits of [al] and save the
- mov al, 0 ; result in [al]. Refer to [convtable].
- mov cx, 7
- convloop:
- shr ah, 1
- jnc conv_cont1
- mov bl, cs:[bp+convtable]
- add al, bl
- daa
- conv_cont1:
- inc bp
- loop convloop
-
- conv_exit:
- mov ah, al
- pop cx
- pop bp
- ret
-
- ;--------------------------------------------------------------------------
-
-
- showword: ;This routine displays a word (AX)
- push ax
- push cx
- mov cl,8
- shr ax,cl
- call showbyte
- pop cx
- pop ax
-
- showbyte: ;This routine displays a byte (AL)
- push ax
- push cx
- mov cl,4
- shr al,cl
- call shownib
- pop cx
- pop ax
-
- shownib: ;This routine displays lower nibble(AL)
- push ax
- push dx
-
- and al, 0Fh
- mov dl,'0'
- cmp al,0Ah ;Hm.. need higher OR value? for hex digit
- jl show_c1
- mov dl,('A'-10)
-
- show_c1:
- add dl,al
- mov al, dl
- call display_al
- pop dx
- pop ax
- ret
-
- display_al:
- push ax ;This routines displays an ascii byte (AL)
- push bx
- push bp
- pushf
-
- push ax
- mov ah, 0Fh
- int screen
- mov ah, 08h
- int screen
- mov bl, al
- pop ax
- mov ah, 0Eh
- int screen
-
- popf
- pop bp
- pop bx
- pop ax
- ret
-
- ;--------------------------------------------------------------------------
-
- click: ; IN=none, OUT=none, all regs preserved.
- push ax
- push cx
-
- mov al, 10110110b
- out timer+3, al
- mov ax, 0777h ; this is the frequency of the tone
- out timer+2, al
- mov al, ah
- out timer+2, al
- in al, port_b
- mov ah, al
- or al, 03h
- out port_b, al
- mov cx, 0018h ; this is the duration of the tone
- loop $
- mov al, ah
- out port_b, al
-
- pop cx
- pop ax
- ret
-
-
- ;-------------------------------- ENDS ----------------------------------
-
- db 0 ; this is here for the DOS terminate-and-
- veryend: ; stay-resident function to work properly.
- code ends
- end start
- ;------------------------------ ROUTINES --------------------------------